package com.example.cm_player

import android.media.MediaPlayer
import android.util.Log

/**
 * 具有状态的MediaPlayer
 */
class StateMediaPlayer : MediaPlayer() {
    companion object {
        private const val TAG = "StateMediaPlayer"
    }

    enum class State {
        IDLE, INITIALIZED, PREPARING, PREPARED,
        STARTED, PAUSED, STOPPED, COMPLETED, ERROR, END
    }

    private var currentState = State.IDLE
    private var onStateChanged: ((State) -> Unit)? = null
    private var errorHandler: ErrorHandler? = null

    private var customPreparedListener: OnPreparedListener? = null
    private var customCompletionListener: OnCompletionListener? = null
    private var customErrorListener: OnErrorListener? = null

    init {
        super.setOnPreparedListener { mp ->
            updateState(State.PREPARED)
            customPreparedListener?.onPrepared(mp)
        }
        super.setOnCompletionListener { mp ->
            updateState(State.COMPLETED)
            customCompletionListener?.onCompletion(mp)
        }
        super.setOnErrorListener { mp, what, extra ->
            updateState(State.ERROR)
            customErrorListener?.onError(mp, what, extra) ?: handleDefaultError(what, extra)
        }
    }


    fun setOnStateChanged(listener: (State) -> Unit) {
        onStateChanged = listener
    }

    fun setErrorHandler(handler: ErrorHandler) {
        errorHandler = handler
    }

    fun setPreparedListener(listener: OnPreparedListener) {
        customPreparedListener = listener
    }

    fun setCompletionListener(listener: OnCompletionListener) {
        customCompletionListener = listener
    }

    fun setErrorListener(listener: OnErrorListener) {
        customErrorListener = listener
    }

    fun getState() = currentState


    override fun reset() {
        if (currentState == State.END) {
            throw IllegalStateException("Cannot reset after release")
        }
        super.reset()
        updateState(State.IDLE)
    }

    override fun setDataSource(path: String) {
        if (currentState != State.IDLE) {
            throw IllegalStateException("Must be in IDLE state to set data source")
        }
        super.setDataSource(path)
        updateState(State.INITIALIZED)
    }

    override fun prepareAsync() {
        if (currentState != State.INITIALIZED && currentState != State.STOPPED) {
            throw IllegalStateException("Can only prepareAsync when initialized or stopped")
        }
        super.prepareAsync()
        updateState(State.PREPARING)
    }

    override fun prepare() {
        if (currentState != State.INITIALIZED && currentState != State.STOPPED) {
            throw IllegalStateException("Can only prepare when initialized or stopped")
        }
        super.prepare()
        updateState(State.PREPARED)
    }

    override fun start() {
        if (currentState != State.PREPARED && currentState != State.PAUSED && currentState != State.COMPLETED) {
            throw IllegalStateException("Can only start when prepared, paused or completed")
        }
        super.start()
        updateState(State.STARTED)
    }

    override fun pause() {
        if (currentState != State.STARTED) {
            throw IllegalStateException("Can only pause when started")
        }
        super.pause()
        updateState(State.PAUSED)
    }

    override fun stop() {
        if (currentState != State.PREPARED && currentState != State.STARTED && currentState != State.PAUSED && currentState != State.COMPLETED) {
            throw IllegalStateException("Can only stop when prepared, started, paused or completed")
        }
        super.stop()
        updateState(State.STOPPED)
    }

    override fun seekTo(msec: Int) {
        if (currentState != State.PREPARED && currentState != State.STARTED && currentState != State.PAUSED && currentState != State.COMPLETED) {
            throw IllegalStateException("Can only seekTo when prepared, started, paused or completed")
        }
        super.seekTo(msec)
        updateState(currentState)
    }

    override fun release() {
        super.release()
        updateState(State.END)
        cleanup()
    }


    @Deprecated("Use setPreparedListener instead", level = DeprecationLevel.ERROR)
    override fun setOnPreparedListener(listener: OnPreparedListener?) = unsupported()

    @Deprecated("Use setCompletionListener instead", level = DeprecationLevel.ERROR)
    override fun setOnCompletionListener(listener: OnCompletionListener?) = unsupported()

    @Deprecated("Use setErrorListener instead", level = DeprecationLevel.ERROR)
    override fun setOnErrorListener(listener: OnErrorListener?) = unsupported()

    @Synchronized
    private fun updateState(newState: State) {
        Log.d(TAG, "State changed: $currentState → $newState")
        currentState = newState
        onStateChanged?.invoke(newState)
    }

    private fun handleDefaultError(what: Int, extra: Int): Boolean {
        return when (what) {
            MEDIA_ERROR_SERVER_DIED -> {
                release()
                true
            }
            else -> errorHandler?.onError(what, extra) ?: false
        }
    }

    private fun cleanup() {
        onStateChanged = null
        errorHandler = null
        customPreparedListener = null
        customCompletionListener = null
        customErrorListener = null
    }

    private fun unsupported(): Nothing =
        throw UnsupportedOperationException("Use custom listener setters instead")

    interface ErrorHandler {
        fun onError(what: Int, extra: Int): Boolean
    }
}